OnWeight · Design Foundations

Foundations
& tokens

The canonical values behind every OnWeight screen — colour, type, spacing, radii, shadow and motion. These are the Balanced theme tokens, the shipping direction used across All Screens and the Prototype. Copy them straight into a platform Theme. (Two alternate themes — Classic, Full-Editorial — exist in fc-shared.jsx; Balanced is the one to build.)

01 Colour

A warm-paper neutral ramp, near-black ink, one red accent, and a green/amber/red tone set for pace verdicts. We target WCAG 2.2 AA as a minimum and AAA wherever possible — every core text pairing below clears AA, and most clear AAA (ratios shown).

Surfaces & ink

Paper
#FFFFFF · --paper
Card / sheet surface
Paper-2
#F1EDE6 · --paper-2
Page surface behind cards
Ink
#15140F · --ink
Primary text · 18.4:1
Ink-2
#3A3833 · --ink-2
Secondary text · 11.7:1
Ink-3
#524D44 · --ink-3
Captions / muted · 8.4:1
Rule
#E6DED2 · --rule
Hairlines / dividers
Rule-2
#8A7F68 · --rule-2
Borders / icons only · 3.95:1, never text
Accent
#A32A18 · --accent
Red · links, CTAs, the one pop · 7.2:1

Pace tones — verdict system

Green
#2F5A24 · --t-green
On track · 8.1:1
soft 13%
Amber
#6F5210 · --t-amber
Behind / too fast · 7.3:1
soft 15%
Red
#A32A18 · --t-red
Off the pace · genuine risk only
soft 11%
Mustard-deep
#A87B22 · --mustard-deep
Reserved data accent

Rule

Meaning is never carried by colour alone — every pace verdict pairs its tone with a word (“Making weight”, “Off the pace”). Red is reserved for genuine risk; the soft tints (11–15% alpha) are for badge/callout fills, never text.

Hero vs primary action

One red action only: the Hero button — logging today's weight, the daily habit the app is built around. Every other primary action uses ink (PrimaryButton). Red never competes with itself on a screen. See Component Specs.

Cycle & instrument palette

The menstrual-cycle visuals carry a four-phase palette, and two onboarding/instrument accents sit outside the core tokens. Logged here so they are part of the system, not loose values in the code.

Menstrual
#B0432F
Phase band / marker
Follicular
#6B8F5A
Phase band / marker
Ovulation
#C79A3A
Phase band / marker
Luteal
#7A6AA0
Phase band / marker (the purple)
Pace-gold
#C9A23A
Pace-scale gradient mid (on dark)
Pace-brick
#B0432F
Pace-scale gradient end
Inverted red
#F4A299 on ink
Accent on dark surfaces only

These are graphics, not text

Phase colours appear as bands at ~12% opacity and as full-strength ring/markers — never as body text. Ovulation and Follicular fail AA as text on light, so they only ever sit behind a text label or position (which also serves colour-blind athletes). Pace-gold #C9A23A and inverted red #F4A299 are legible only on ink/dark and are used there exclusively.

Opacity scale

Fills and overlays use a small, consistent set of alphas so charts and tints feel like one hand drew them.

AlphaWhere
0.10–0.14Target-zone & tone-band fills, soft callout tints, cycle phase bands (0.12)
0.26–0.40Raw weigh-in dots on the trend (recessive)
~0.40Scrubber / today divider lines
0.50–0.70Gridlines & hairlines inside charts
0.14 → 0.03 → 0Trend-area gradient fill (top → fade)
0.045–0.05Poster hatch / grid motif overlays

Contrast · WCAG 2.2

Computed ratios for every text/icon colour against the three real surfaces. AA needs ≥ 4.5:1 (normal text), AAA ≥ 7:1; non-text graphics need ≥ 3:1. This is why status text uses --t-amber #6F5210 while chart strokes use --mustard-deep #A87B22 (a graphic).

Foregroundon Paper #fffon Page #f9f7f2on Ink #15140f
Ink #15140F18.4 · AAA17.2 · AAA
Ink-2 #3A383311.7 · AAA10.9 · AAA
Ink-3 #524D448.4 · AAA7.8 · AAA
Accent #A32A187.2 · AAA6.8 · AA2.6 · graphic-fail
Green #2F5A248.1 · AAA7.5 · AAA
Amber-text #6F52107.3 · AAA6.8 · AA
Mustard-deep #A87B223.8 · graphic only3.6 · graphic only4.9 · AA
Rule-2 #8A7F683.95 · graphic only3.7 · graphic only4.7 · AA
Menstrual #B0432F5.7 · AA5.3 · AA3.2 · graphic
Luteal #7A6AA04.8 · AA4.5 · AA*3.9 · graphic
Follicular #6B8F5A3.7 · graphic only3.4 · graphic only5.0 · AA
Ovulation #C79A3A2.6 · fail2.4 · fail7.1 · AAA

*Luteal on the off-white page is 4.46 — a hair under AA for small text; it is only used as a band/marker, never as body text. “Graphic” = clears the 3:1 bar for non-text UI (icons, strokes, borders) but not the 4.5:1 text bar. Ratios recomputed June 2026; see Accessibility Pass for the policy.

02 Type

Three families: Oswald (eyebrows & section labels), IBM Plex Sans (UI text & the big numerals, with tnum tabular figures), IBM Plex Mono (data labels & meta). IBM Plex Serif appears only in the coach's-read quote. Map each role to a scalable text style — never a literal px — with an 11px floor (see Accessibility Pass).

76.0
Hero numeralPlex Sans · 300 · 96px
lh 0.92 · -0.02em · tnum
Today's weight
Hi, Alex
Large titlePlex Sans · 700 · 28px
-0.03em · screen titles
Making weight
Heading / verdictPlex Sans · 600 · 17px
card headlines
A safe, steady pace. You make weight without draining your power.
BodyPlex Sans · 400 · 15–16px
lh 1.5 · ink-2
Target eased this week for your luteal phase.
CaptionPlex Sans · 400 · 12.5px
ink-3
In camp · Day 1
EyebrowOswald · 600 · 11px
0.16em · uppercase
50 days out
Mono labelPlex Mono · 600 · 10.5–11px
0.08–0.1em · uppercase · data & meta
“Three down. Don't chase the daily number.”
Coach quotePlex Serif · italic · 15px
corner-coach voice only

Numerals use tabular figures (font-feature-settings:"tnum") everywhere they change, so values don't reflow. Body uses text-wrap:pretty; titles text-wrap:balance.

03 Spacing

A 4px base scale. Card padding sits at 18–22, screen gutters at 20, stacked-card gaps at 18–20. Touch targets never below 44pt.

4 · xs
icon insets, tight gaps
8 · sm
label↔value, chip padding
12 · md
inter-element gap, grid gap
16 · lg
card inner padding (compact)
20 · xl
screen gutter, card gap
22 · 2xl
hero card padding
32 · 3xl
section breaks, CTA blocks
TargetMin sizeNotes
Primary CTA54–56pxFull-width buttons
List row50px+Tap-through rows
Icon button44×44ptBack/close visual 38px → expand hit area to 44

04 Radii, elevation & motion

Card radius
20px · --radius
Control radius
14px · --radius-ctl
Pill
100px · badges, toggles
Card shadow
0 1px 3px / 0 8px 22px rgba(20,18,12,.04–.05)
Inverted card
--ink surface, paper text
Hairline border
1px --rule (Balanced uses shadow, not border)
Motion tokenValueUse
Transition · base260ms · cubic-bezier(0.22,0.61,0.36,1)Screen/state changes, slide-in
Transition · fast150ms · easeHovers, small affordances
Reduced motionprefers-reduced-motionDrop entrance animations to instant — always honoured

No infinite decorative loops on content. Entrance animations animate from hidden to the visible base state, gated on reduced-motion so print/PDF/AT show content.

05 Token reference (Balanced)

Verbatim from fc-shared.jsxTHEMES.balanced.vars. Drop into a platform theme as-is.

--paper / --paper-2#ffffff / #f1ede6
--ink / --ink-2 / --ink-3#15140f / #3a3833 / #524d44
--rule / --rule-2#e6ded2 / #8a7f68
--accent / --accent-soft#a32a18 / rgba(163,42,24,0.10)
--t-green / -soft#2f5a24 / rgba(58,107,46,0.13)
--t-amber / -soft#6f5210 / rgba(168,123,34,0.15)
--t-red / -soft#a32a18 / rgba(163,42,24,0.11)
--radius / --radius-ctl20px / 14px
--card-shadow0 1px 3px rgba(20,18,12,.04), 0 8px 22px rgba(20,18,12,.05)
--display / --num / --titleOswald / IBM Plex Sans / IBM Plex Sans
--title-spacing / --eyebrow-spacing-0.03em / 0.16em

Companion to the component specs (next), the Accessibility Pass (contrast ratios cited above), and fc-shared.jsx (source of truth).

OnWeight HQ